{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 样本均衡对逻辑回归、决策树、SVM的影响\n",
    "(https://www.joinquant.com/view/community/detail/4043496725b8121f04bb1d8f6568247c)\n",
    "\n",
    "该文仅用于对作者结论的分析，故暂不做分红接取聚宽数据及动态时间获取处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 若当前环境没有此包，执行一下命令一次，并重启\n",
    "# !pip install imblearn --user"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import datetime\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.svm import SVC\n",
    "from sklearn.model_selection import StratifiedKFold\n",
    "from sklearn.feature_selection import RFECV\n",
    "from sklearn import preprocessing\n",
    "from imblearn.over_sampling import SMOTE  # 过抽样处理库SMOTE\n",
    "from collections import Counter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.数据获取及预处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.1 分红数据获取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 获取年末分红数据 ###\n",
    "div_data = pd.read_csv(r'./data/Div_data.csv',index_col=0)\n",
    "div_data.head(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "##只留年报数据\n",
    "div_data['type'] = div_data['endDate'].map(lambda x:x[-5:]) #截取endDate第五个字符至结尾\n",
    "div_data['year'] = div_data['endDate'].map(lambda x:x[0:4]) #截取endDate前四个字符\n",
    "div_data.head(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "div_data_year = div_data[div_data['type'] == '12-31'] #找出报告时间是年末的定义为年报\n",
    "div_data_year = div_data_year[['secID','year','publishDate', 'recordDate','perShareDivRatio',\n",
    "       'perShareTransRatio']]\n",
    "# 最后两列分别为送股、转股\n",
    "div_data_year.columns = ['stock','year','pub_date','execu_date','sg_ratio','zg_ratio']\n",
    "div_data_year.fillna(0,inplace = True)\n",
    "div_data_year.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 获取高送转数据 ###\n",
    "#定义送转列：10送X+10转X合计\n",
    "div_data_year['sz_ratio'] = div_data_year['sg_ratio']+div_data_year['zg_ratio']\n",
    "# 定义是否高送转列（初始值为0）\n",
    "div_data_year['gsz'] = 0\n",
    "\n",
    "#高送转定义：10送X+10转X大于等于10，即定义为高送转\n",
    "div_data_year.loc[div_data_year['sz_ratio'] >=1,'gsz'] = 1\n",
    "div_data_year.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#删除不需要列\n",
    "div_data_year = div_data_year.drop(['sz_ratio', 'sg_ratio', 'zg_ratio'], axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "div_data_year.describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.2 财务数据获取\n",
    "财务指标参考API https://www.joinquant.com/help/api/help#Stock:%E8%8E%B7%E5%8F%96%E5%8D%95%E5%AD%A3%E5%BA%A6%E5%B9%B4%E5%BA%A6%E8%B4%A2%E5%8A%A1%E6%95%B0%E6%8D%AE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "###将一些指标转变为每股数值， need_indicator 调用该函数时传入的指标名称\n",
    "# param old_name 为JQ财务指标名，new_name为本研究定义的每股指标数值\n",
    "def get_perstock_indicator(need_indicator,old_name,new_name,sdate):\n",
    "    target = get_fundamentals(\n",
    "        query(valuation.code,\n",
    "              valuation.capitalization, #总股本，单位为万股，后续需要*10000\n",
    "              need_indicator), \n",
    "        statDate = sdate)\n",
    "    target[new_name] = target[old_name]/target['capitalization']/10000\n",
    "    \n",
    "    return target[['code',new_name]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 特拉仔 新增，用于get_perstock_indicator()测试\n",
    "#每股资本公积\n",
    "per_zbgj = get_perstock_indicator(balance.capital_reserve_fund,'capital_reserve_fund','per_CapitalReserveFund','2016q3')\n",
    "per_zbgj.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "###获取每股收益、股本数量、营业收入同比增长、净利润同比增长\n",
    "# @特拉仔 这个函数调用的query过滤条件，只是指定了上述四个参数，后续需要注意是否有返回数据条数限制\n",
    "def get_other_indicator(sdate):\n",
    "    target = get_fundamentals(\n",
    "        query(valuation.code,\n",
    "              valuation.capitalization,\n",
    "              indicator.inc_revenue_year_on_year,\n",
    "              indicator.inc_net_profit_year_on_year,\n",
    "              indicator.eps),\n",
    "        statDate = sdate)\n",
    "    \n",
    "    # 营业收入同比增长\n",
    "    target.rename(columns={'inc_revenue_year_on_year':'revenue_growth'},inplace = True)\n",
    "    # 净利润同比增长\n",
    "    target.rename(columns={'inc_net_profit_year_on_year':'profit_growth'},inplace = True)      \n",
    "    # 股本数量\n",
    "    target['capitalization'] = target['capitalization']*10000\n",
    "    \n",
    "    return target[['code','capitalization','eps','revenue_growth','profit_growth']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "###获取一个月收盘价平均值\n",
    "def get_bmonth_aprice(code_list,startdate,enddate):\n",
    "    mid_data = get_price(code_list, start_date=startdate, end_date=enddate,\\\n",
    "              frequency='daily', fields='close', skip_paused=False, fq='pre')\n",
    "    mean_price = pd.DataFrame(mid_data['close'].mean(axis = 0),columns=['mean_price'])\n",
    "    mean_price['code'] =mean_price.index\n",
    "    mean_price.reset_index(drop = True,inplace =True)\n",
    "    \n",
    "    return mean_price[['code','mean_price']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "###判断是否为次新股（判断标准为位于上市一年之内）                          \n",
    "def judge_cxstock(date):\n",
    "    mid_data = get_all_securities(types=['stock'])\n",
    "    mid_data['start_date'] = mid_data['start_date'].map(lambda x:x.strftime(\"%Y-%m-%d\"))\n",
    "    shift_date = str(int(date[0:4])-1)+date[4:]\n",
    "    mid_data['1year_shift_date'] = shift_date\n",
    "    mid_data['cx_stock'] = 0 #次新股标记\n",
    "    mid_data.loc[mid_data['1year_shift_date']<=mid_data['start_date'],'cx_stock'] = 1\n",
    "    mid_data['code'] = mid_data.index\n",
    "    mid_data.reset_index(drop = True,inplace=True)\n",
    "\n",
    "    return mid_data[['code','cx_stock']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "code_folding": [
     2
    ]
   },
   "outputs": [],
   "source": [
    "###判断上市了多少个自然日\n",
    "from datetime import date\n",
    "def get_dayslisted(year,month,day):\n",
    "    mid_data = get_all_securities(types=['stock'])\n",
    "    sdate = date(year,month,day)\n",
    "    mid_data['days_listed'] = mid_data['start_date'].map(lambda x:(sdate -x).days)\n",
    "    mid_data['code'] = mid_data.index\n",
    "    mid_data.reset_index(drop = True,inplace=True)\n",
    "    \n",
    "    return mid_data[['code','days_listed']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "输入：所需财务报表期、20日平均股价开始日期、20日平均股价结束日期\n",
    "输出：合并好的高送转数据 以及 财务指标数据\n",
    "\"\"\"\n",
    "def get_yearly_totaldata(statDate,statDate_before,mp_startdate,mp_enddate,year,month,day):\n",
    "    \n",
    "    #\n",
    "    #有能力高送转，基础指标包括：每股资本公积，每股留存收益\n",
    "    #\n",
    "    #每股资本公积\n",
    "    per_zbgj = get_perstock_indicator(balance.capital_reserve_fund,'capital_reserve_fund','per_CapitalReserveFund',statDate)\n",
    "    #每股留存收益\n",
    "    per_wflr = get_perstock_indicator(balance.retained_profit,'retained_profit','per_RetainProfit',statDate)\n",
    "    #\n",
    "    #有能力高送转，其他指标包括：每股净资产、每股收益、营业收入同比增速、净利润同比增速\n",
    "    #\n",
    "    #每股净资产\n",
    "    per_jzc = get_perstock_indicator(balance.equities_parent_company_owners,'equities_parent_company_owners','per_TotalOwnerEquity',statDate) \n",
    "    #每股收益、股本、营业收入同比增长、净利润同比增速\n",
    "    other_indicator = get_other_indicator(statDate)\n",
    "    code_list = other_indicator['code'].tolist()\n",
    "    #\n",
    "    #有意愿高送转，指标包括均价、上市时间、股本增加\n",
    "    #均价\n",
    "    mean_price = get_bmonth_aprice(code_list,mp_startdate,mp_enddate)\n",
    "    #是否为次新股\n",
    "    cx_signal = judge_cxstock(mp_enddate)\n",
    "    #股本增加\n",
    "    #dz_signal = judge_dz(statDate,statDate_before)\n",
    "    #上市时间\n",
    "    days_listed = get_dayslisted(year,month,day)\n",
    "    #\n",
    "    #因子列表：\n",
    "    #每股资本公积\n",
    "    #每股留存收益\n",
    "    #每股净资产\n",
    "    #每股收益、股本\n",
    "    #均价\n",
    "    #是否为次新股\n",
    "    #上市时间\n",
    "    chart_list = [per_zbgj,per_wflr,per_jzc,other_indicator,mean_price,cx_signal,days_listed]\n",
    "\n",
    "    for chart in chart_list:\n",
    "        chart.set_index('code',inplace = True)\n",
    "\n",
    "    independ_vari = pd.concat([per_zbgj,per_wflr,per_jzc,other_indicator,mean_price,cx_signal,days_listed],axis = 1)\n",
    "    independ_vari['year'] = str(int(statDate[0:4]))\n",
    "    independ_vari['stock'] = independ_vari.index\n",
    "    independ_vari.reset_index(drop=True,inplace =True)\n",
    "\n",
    "    total_data = pd.merge(div_data_year,independ_vari,on = ['stock','year'],how = 'inner')\n",
    "    \n",
    "    # 每股资本公积 + 每股留存收益\n",
    "    total_data['per_zbgj_wflr'] = total_data['per_CapitalReserveFund']+total_data['per_RetainProfit']\n",
    "    \n",
    "    return total_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gsz_2016 = get_yearly_totaldata('2016q3','2015q3','2016-10-01','2016-11-01',2016,11,1)\n",
    "gsz_2015 = get_yearly_totaldata('2015q3','2014q3','2015-10-01','2015-11-01',2015,11,1)\n",
    "gsz_2014 = get_yearly_totaldata('2014q3','2013q3','2014-10-01','2014-11-01',2014,11,1)\n",
    "gsz_2013 = get_yearly_totaldata('2013q3','2012q3','2013-10-01','2013-11-01',2013,11,1)\n",
    "gsz_2012 = get_yearly_totaldata('2012q3','2011q3','2012-10-01','2012-11-01',2012,11,1)\n",
    "gsz_2011 = get_yearly_totaldata('2011q3','2010q3','2011-10-01','2011-11-01',2011,11,1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.模型预测 #"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.1 训练集及验证集数据做成"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "gszData = pd.concat([gsz_2011,gsz_2012,gsz_2013,gsz_2014,gsz_2015,gsz_2016],axis = 0)\n",
    "gszData.dropna(inplace = True)\n",
    "\n",
    "variable_list = ['per_zbgj_wflr','capitalization', 'eps', 'revenue_growth','profit_growth','mean_price', 'days_listed']\n",
    "\n",
    "X = gszData.loc[:,variable_list]\n",
    "y = gszData.loc[:,'gsz']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gszData.head(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这里只是为了展示每列的中文含义\n",
    "gsz_cn = gszData.copy(deep=True)\n",
    "gsz_cn.columns = ['股票代码', '年份', '发布日期', '执行日期', '高转送标识', '每股资本公积', '每股留存收益', '股东权益合计(元)', '总股本', '每股收益', '营业收入同比增长', '净利润同比增长', '均价', '次新股标识', '上市时长', '每股资本公积+留存收益']\n",
    "gsz_cn.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X.head(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# print(type(y))\n",
    "# y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 样本均衡前"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看数据分布\n",
    "# Counter是对字典类型的补充，用于追踪值的出现次数。\n",
    "# 具备字典的所有功能 + 自己的功能。\n",
    "print(Counter(y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于样本均衡前的数据进行训练集和测试集划分\n",
    "X_train_1, X_test_1, y_train_1, y_test_1 = train_test_split(X,y,random_state=19)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看数据分布\n",
    "print(Counter(y_train_1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看数据分布\n",
    "print(Counter(y_test_1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2 样本均衡后\n",
    "@特拉仔——样本均衡后的数据分布与前比较"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 样本均衡方法\n",
    "def sample_balance(X, y):\n",
    "    '''\n",
    "    使用SMOTE方法对不均衡样本做过抽样处理\n",
    "    :param X: 输入特征变量X\n",
    "    :param y: 目标变量y\n",
    "    :return: 均衡后的X和y\n",
    "    '''\n",
    "    model_smote = SMOTE()  # 建立SMOTE模型对象\n",
    "    # 注意这里作者不是对tran test split后的X，y做样本均衡，而是在这之前    \n",
    "    x_smote_resampled, y_smote_resampled = model_smote.fit_resample(X, y)  # 输入数据并作过抽样处理\n",
    "    return x_smote_resampled, y_smote_resampled"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_resampled,y_resampled = sample_balance(X, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看数据分布\n",
    "print(Counter(y_resampled))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于样本均衡后的数据进行训练集和测试集划分\n",
    "X_train_2, X_test_2, y_train_2, y_test_2 = train_test_split(X_resampled,y_resampled,random_state=19)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看数据分布\n",
    "print(Counter(y_train_2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 查看数据分布\n",
    "print(Counter(y_test_2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.3 基于逻辑回归算法预测 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "@ 特拉仔—— sklearn.linear_model.LinearRegression.score 返回该次预测的系数Rsquare\n",
    "\n",
    "从原文的比较结果来看，决策树最优，SVM次之，LR最不适合\n",
    "\n",
    "predict()与predict_proba()用法区别 https://www.cnblogs.com/mrtop/p/10309083.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LogisticRegression\n",
    "# 选择balanced让类库自己计算类型权重\n",
    "model = LogisticRegression(class_weight='balanced',C=1e9)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡前\n",
    "model.fit(X_train_1, y_train_1)\n",
    "print(\"Trainning set score:{:.3f}\".format(model.score(X_train_1, y_train_1)))\n",
    "print(\"     Test set score:{:.3f}\".format(model.score(X_test_1, y_test_1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡后\n",
    "model.fit(X_train_2, y_train_2)\n",
    "print(\"Trainning set score:{:.3f}\".format(model.score(X_train_2, y_train_2)))\n",
    "print(\"     Test set score:{:.3f}\".format(model.score(X_test_2, y_test_2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "predict: 模型预测输入样本所属的类别，是则输出1，不是则输出0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡前\n",
    "y_pred_1 = model.predict(X_test_1)\n",
    "y_pred_1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡后\n",
    "y_pred_2 = model.predict(X_test_2)\n",
    "y_pred_2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 返回预测属于某标签的概率 - 均衡前\n",
    "y_pred_threshold_1 = model.predict_proba(X_test_1)[:,1]\n",
    "len(y_pred_threshold_1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 返回预测属于某标签的概率 - 均衡前\n",
    "y_pred_threshold_2 = model.predict_proba(X_test_2)[:,1]\n",
    "len(y_pred_threshold_2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.3 基于SVM算法预测\n",
    "\n",
    "注：sklearn.svm.SVC 参数注释 \n",
    "https://blog.csdn.net/icanx/article/details/96270752\n",
    "\n",
    "https://blog.csdn.net/github_39261590/article/details/75009069"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#均值方差标准化\n",
    "standard_scaler = preprocessing.StandardScaler()\n",
    "clf = SVC(C=1.0,class_weight='balanced',gamma='auto',kernel='rbf',probability=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "SVM均衡前"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_trainScale_3 = standard_scaler.fit_transform(X_train_1)\n",
    "X_testScale_3 = standard_scaler.transform(X_test_1) \n",
    "\n",
    "clf.fit(X_trainScale_3, y_train_1) \n",
    "\n",
    "print(\"Trainning set score:{:.3f}\".format(clf.score(X_trainScale_3,y_train_1)))\n",
    "print(\"     Test set score:{:.3f}\".format(clf.score(X_testScale_3,y_test_1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_3=clf.predict(X_testScale_3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "decision_function:  帮助文档中给出的解释是“The confidence score for a sample is the signed distance of that sample to the hyperplane.”。意思就是使用样本到分隔超平面的有符号距离来度量预测结果的置信度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_threshold_3 = clf.decision_function(X_testScale_3) \n",
    "y_pred_threshold_3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_changed_threshold_3 = (y_pred_threshold_3 > 0.3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "SVM 均衡后"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_trainScale_4 = standard_scaler.fit_transform(X_train_2)\n",
    "X_testScale_4 = standard_scaler.transform(X_test_2) \n",
    "\n",
    "clf.fit(X_trainScale_4, y_train_2) \n",
    "\n",
    "print(\"Trainning set score:{:.3f}\".format(clf.score(X_trainScale_4,y_train_2)))\n",
    "print(\"     Test set score:{:.3f}\".format(clf.score(X_testScale_4,y_test_2)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_4=clf.predict(X_testScale_4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_threshold_4 = clf.decision_function(X_testScale_4) \n",
    "y_pred_threshold_4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_changed_threshold_4 = (y_pred_threshold_4 > 0.3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.4 基于决策树算法预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.tree import DecisionTreeClassifier\n",
    "\n",
    "tree = DecisionTreeClassifier(random_state=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "决策树均衡前"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tree.fit(X_train_1,y_train_1)\n",
    "print(\"Trainning set score:{:.3f}\".format(tree.score(X_train_1,y_train_1)))\n",
    "print(\"     Test set score:{:.3f}\".format(tree.score(X_test_1,y_test_1)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_5 = tree.predict(X_test_1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "predict_proba:  模型预测输入样本属于每种类别的概率，概率和为1，每个位置的概率分别对应classes_中对应位置的类别标签。以上述类别标签为[2 4 6 8]的那个分类器为例，查看一下分类模型预测的概率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_threshold_5 = tree.predict_proba(X_test_1)[:,1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.tree import export_graphviz\n",
    "import graphviz\n",
    "\n",
    "dot_data = export_graphviz(tree,out_file=None,class_names=[\"GSZ \",\"NOT GSZ\"],feature_names=X_train_1.columns,\n",
    "                          impurity=False,filled=True)\n",
    "graph = graphviz.Source(dot_data) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "决策树均衡后"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tree.fit(X_train_2,y_train_2)\n",
    "print(\"Trainning set score:{:.3f}\".format(tree.score(X_train_2,y_train_2)))\n",
    "print(\"     Test set score:{:.3f}\".format(tree.score(X_test_2,y_test_2)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_6 = tree.predict(X_test_2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_pred_threshold_6 = tree.predict_proba(X_test_2)[:,1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dot_data = export_graphviz(tree,out_file=None,class_names=[\"GSZ \",\"NOT GSZ\"],feature_names=X_train_2.columns,\n",
    "                          impurity=False,filled=True)\n",
    "graph = graphviz.Source(dot_data) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "# @特拉仔新增，保存决策树图至当前目录\n",
    "# graph.render(\"./Data/决策树示例\")    # 生成两个文件，均无法正常显示决策树\n",
    "# graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# with open('./tree.dot','w',encoding='utf-8') as f:\n",
    "#     f=export_graphviz(tree,out_file=f,class_names=[\"GSZ \",\"NOT GSZ\"],feature_names=X_train.columns,\n",
    "#                           impurity=False,filled=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 4.预测评价"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.1 混淆矩阵\n",
    "\n",
    "@特拉仔——混淆矩阵是机器学习中总结分类模型预测结果的情形分析表，以矩阵形式将数据集中的记录按照真实的类别与分类模型作出的分类判断两个标准进行汇总。这个名字来源于它可以非常容易的表明多个类别是否有混淆（也就是一个class被预测成另一个class）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import confusion_matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于逻辑回归的混淆矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡前\n",
    "confusion1 = confusion_matrix(y_test_1,y_pred_1)\n",
    "print(\"Confusion matrix:\\n{}\".format(confusion1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡后\n",
    "confusion2 = confusion_matrix(y_test_2,y_pred_2)\n",
    "print(\"Confusion matrix:\\n{}\".format(confusion2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于SVM的混淆矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡前\n",
    "confusion3 = confusion_matrix(y_test_1,y_pred_3)\n",
    "print(\"Confusion matrix:\\n{}\".format(confusion3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡后\n",
    "confusion4 = confusion_matrix(y_test_2,y_pred_4)\n",
    "print(\"Confusion matrix:\\n{}\".format(confusion4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于决策树的混淆矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡前\n",
    "confusion5 = confusion_matrix(y_test_1,y_pred_5)\n",
    "print(\"Confusion matrix:\\n{}\".format(confusion5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡后\n",
    "confusion6 = confusion_matrix(y_test_2,y_pred_6)\n",
    "print(\"Confusion matrix:\\n{}\".format(confusion6))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.2 准确率、召回率及f1-score统计\n",
    "\n",
    "precision（精度）：关注于所有被预测为正（负）的样本中究竟有多少是正（负）。（分母是预测出的数据）\n",
    "\n",
    "recall（召回率）： 关注于所有真实为正（负）的样本有多少被准确预测出来了。（分母是原数据）\n",
    "\n",
    "f1-score：二者均值。\n",
    "\n",
    "supprot：每个标签的出现次数。\n",
    "\n",
    "avg / total行为各列的均值（support列为总和）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import classification_report"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于逻辑回归的classification_report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡前\n",
    "# print(classification_report(y_test_1,y_pred_1))\n",
    "print(classification_report(y_test_1,y_pred_1, labels=np.unique(y_pred_1)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "/home/jquser/.local/lib/python3.6/site-packages/sklearn/metrics/_classification.py:1248: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.\n",
    "\n",
    "参考https://stackoverflow.com/questions/66022943/how-to-fix-this-classification-report-warning\n",
    "\n",
    "警告的意思是由于存在有label没有被predict使用的情况（label '1' 的值为0），classification_report的输出受到影响。\n",
    "label '1' 为 0， 意味着precision除以0（true positives + false positives = 0）。而需要注意的是， 此0并非真实值，而是表示Undefined之类的情况。同时导致后面计算 macro avg 的计算被引入这个0。\n",
    "\n",
    "要解决这个问题\n",
    "\n",
    "1. 改用StratifiedKFold\n",
    "2. Oversampling（过采样）\n",
    "3. classification_report(y_test, y_pred, labels=np.unique(y_pred)) 添加第三个参数labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# StratifiedKFold\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡后\n",
    "print(classification_report(y_test_2,y_pred_2, labels=np.unique(y_pred_2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于SVM的classification_report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡前\n",
    "print(classification_report(y_test_1,y_pred_3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡后\n",
    "print(classification_report(y_test_2,y_pred_4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于决策树的classification_report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡前\n",
    "print(classification_report(y_test_1,y_pred_5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 均衡后\n",
    "print(classification_report(y_test_2,y_pred_6))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.3 准确率-召回率曲线\n",
    "\n",
    "y_pred_threshold 实例在每个类中的概率，因此实际上预测值（类）取决于该概率而另一个值称为阈值 . \n",
    "\n",
    "y_pred_threshold 大于阈值的所有实例都分为一类，而另一类则更小 . 默认阈值为0.5\n",
    "\n",
    "改变阈值我们有不同的预测结果 . 在许多问题中，通过调整阈值可以获得更好的结果 . 这就是为您提供precision_recall_curve的原因 .\n",
    "\n",
    "thresholdsndarray of shape (n_thresholds,)\n",
    "\n",
    "Increasing thresholds on the decision function used to compute precision and recall. n_thresholds <= \n",
    "\n",
    "len(np.unique(probas_pred))."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import precision_recall_curve"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于逻辑回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡前\n",
    "precision,recall,thresholds = precision_recall_curve(y_test_1,y_pred_threshold_1)\n",
    "\n",
    "plt.plot(precision,recall,label=\"准确率-召回率曲线\")\n",
    "plt.xlabel(\"准确率\")\n",
    "plt.ylabel(\"召回率\")\n",
    "\n",
    "# np.argmin 给出axis方向最小值的下标， axis默认None，此时返回0\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(precision[close_zero],recall[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "thresholds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡后\n",
    "precision,recall,thresholds = precision_recall_curve(y_test_2,y_pred_threshold_2)\n",
    "\n",
    "plt.plot(precision,recall,label=\"准确率-召回率曲线\")\n",
    "plt.xlabel(\"准确率\")\n",
    "plt.ylabel(\"召回率\")\n",
    "\n",
    "# np.argmin 给出axis方向最小值的下标， axis默认None，此时返回0\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(precision[close_zero],recall[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "thresholds"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于SVM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡前\n",
    "precision,recall,thresholds = precision_recall_curve(y_test_1,y_pred_threshold_3)\n",
    "\n",
    "plt.plot(precision,recall,label=\"准确率-召回率曲线\")\n",
    "plt.xlabel(\"准确率\")\n",
    "plt.ylabel(\"召回率\")\n",
    "\n",
    "# np.argmin 给出axis方向最小值的下标， axis默认None，此时返回0\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(precision[close_zero],recall[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "thresholds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡后\n",
    "precision,recall,thresholds = precision_recall_curve(y_test_2,y_pred_threshold_4)\n",
    "\n",
    "plt.plot(precision,recall,label=\"准确率-召回率曲线\")\n",
    "plt.xlabel(\"准确率\")\n",
    "plt.ylabel(\"召回率\")\n",
    "\n",
    "# np.argmin 给出axis方向最小值的下标， axis默认None，此时返回0\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(precision[close_zero],recall[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "thresholds"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于决策树"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡前\n",
    "precision,recall,thresholds = precision_recall_curve(y_test_1,y_pred_threshold_5)\n",
    "\n",
    "plt.plot(precision,recall,label=\"准确率-召回率曲线\")\n",
    "plt.xlabel(\"准确率\")\n",
    "plt.ylabel(\"召回率\")\n",
    "\n",
    "# np.argmin 给出axis方向最小值的下标， axis默认None，此时返回0\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(precision[close_zero],recall[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "thresholds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡后\n",
    "precision,recall,thresholds = precision_recall_curve(y_test_2,y_pred_threshold_6)\n",
    "\n",
    "plt.plot(precision,recall,label=\"准确率-召回率曲线\")\n",
    "plt.xlabel(\"准确率\")\n",
    "plt.ylabel(\"召回率\")\n",
    "\n",
    "# np.argmin 给出axis方向最小值的下标， axis默认None，此时返回0\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(precision[close_zero],recall[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "thresholds"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.4 ROC曲线和AUC"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import roc_auc_score\n",
    "from sklearn.metrics import roc_curve"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于逻辑回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡前\n",
    "fpr,tpr,thresholds = roc_curve(y_test_1,y_pred_threshold_1)\n",
    "\n",
    "plt.plot(fpr,tpr,label=\"ROC Curve\")\n",
    "plt.xlabel(\"FPR\")\n",
    "plt.ylabel(\"TPR(recall)\")\n",
    "\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(fpr[close_zero],tpr[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)\n",
    "\n",
    "auc = roc_auc_score(y_test_1,y_pred_threshold_1)\n",
    "print(\"AUC is :{:.3f}\".format(auc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡后\n",
    "fpr,tpr,thresholds = roc_curve(y_test_2,y_pred_threshold_2)\n",
    "\n",
    "plt.plot(fpr,tpr,label=\"ROC Curve\")\n",
    "plt.xlabel(\"FPR\")\n",
    "plt.ylabel(\"TPR(recall)\")\n",
    "\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(fpr[close_zero],tpr[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)\n",
    "\n",
    "auc = roc_auc_score(y_test_1,y_pred_threshold_2)\n",
    "print(\"AUC is :{:.3f}\".format(auc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于SVM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡前\n",
    "fpr,tpr,thresholds = roc_curve(y_test_1,y_pred_threshold_3)\n",
    "\n",
    "plt.plot(fpr,tpr,label=\"ROC Curve\")\n",
    "plt.xlabel(\"FPR\")\n",
    "plt.ylabel(\"TPR(recall)\")\n",
    "\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(fpr[close_zero],tpr[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)\n",
    "\n",
    "auc = roc_auc_score(y_test_1,y_pred_threshold_3)\n",
    "print(\"AUC is :{:.3f}\".format(auc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡后\n",
    "fpr,tpr,thresholds = roc_curve(y_test_2,y_pred_threshold_4)\n",
    "\n",
    "plt.plot(fpr,tpr,label=\"ROC Curve\")\n",
    "plt.xlabel(\"FPR\")\n",
    "plt.ylabel(\"TPR(recall)\")\n",
    "\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(fpr[close_zero],tpr[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)\n",
    "\n",
    "auc = roc_auc_score(y_test_1,y_pred_threshold_4)\n",
    "print(\"AUC is :{:.3f}\".format(auc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "基于决策树"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡前\n",
    "fpr,tpr,thresholds = roc_curve(y_test_1,y_pred_threshold_5)\n",
    "\n",
    "plt.plot(fpr,tpr,label=\"ROC Curve\")\n",
    "plt.xlabel(\"FPR\")\n",
    "plt.ylabel(\"TPR(recall)\")\n",
    "\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(fpr[close_zero],tpr[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)\n",
    "\n",
    "auc = roc_auc_score(y_test_1,y_pred_threshold_5)\n",
    "print(\"AUC is :{:.3f}\".format(auc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 平衡后\n",
    "fpr,tpr,thresholds = roc_curve(y_test_2,y_pred_threshold_6)\n",
    "\n",
    "plt.plot(fpr,tpr,label=\"ROC Curve\")\n",
    "plt.xlabel(\"FPR\")\n",
    "plt.ylabel(\"TPR(recall)\")\n",
    "\n",
    "close_zero = np.argmin(np.abs(thresholds))\n",
    "plt.plot(fpr[close_zero],tpr[close_zero],'o',markersize=10,label=\"threshold zero\",fillstyle=\"none\",c='k',mew=2)\n",
    "\n",
    "auc = roc_auc_score(y_test_1,y_pred_threshold_6)\n",
    "print(\"AUC is :{:.3f}\".format(auc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 5.2017年预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "###取出2017年数据\n",
    "statDate = '2017q3'\n",
    "mp_startdate = '2017-10-01' \n",
    "mp_enddate = '2017-11-01'\n",
    "year = 2017\n",
    "month = 11 \n",
    "day = 1\n",
    "\n",
    "per_zbgj = get_perstock_indicator(balance.capital_reserve_fund,'capital_reserve_fund','per_CapitalReserveFund',statDate)\n",
    "per_wflr = get_perstock_indicator(balance.retained_profit,'retained_profit','per_RetainedProfit',statDate)\n",
    "per_jzc = get_perstock_indicator(balance.total_owner_equities,'total_owner_equities','per_TotalOwnerEquity',statDate)\n",
    "other_indicator = get_other_indicator(statDate)\n",
    "code_list = other_indicator['code'].tolist()\n",
    "mean_price = get_bmonth_aprice(code_list,mp_startdate,mp_enddate)\n",
    "cx_signal = judge_cxstock(mp_enddate)\n",
    "days_listed = get_dayslisted(year,month,day)\n",
    "\n",
    "chart_list = [per_zbgj,per_wflr,per_jzc,other_indicator,mean_price,cx_signal,days_listed]\n",
    "for chart in chart_list:\n",
    "    chart.set_index('code',inplace = True)\n",
    "\n",
    "independ_vari = pd.concat([per_zbgj,per_wflr,per_jzc,other_indicator,mean_price,cx_signal,days_listed],axis = 1)\n",
    "independ_vari['year'] = str(int(statDate[0:4]))\n",
    "independ_vari['stock'] = independ_vari.index\n",
    "independ_vari.reset_index(drop=True,inplace =True)\n",
    "\n",
    "independ_vari['per_zbgj_wflr'] = independ_vari['per_CapitalReserveFund']+independ_vari['per_RetainedProfit']\n",
    "\n",
    "gsz_2017 = independ_vari\n",
    "gsz_2017.loc[gsz_2017['revenue_growth']>300,'revenue_growth'] = 300\n",
    "\n",
    "testdata = gsz_2017\n",
    "testdata.dropna(inplace = True)\n",
    "\n",
    "###利用决策树做预测\n",
    "X_2017 = testdata[variable_list]\n",
    "y_2017 = tree.predict(X_2017)\n",
    "y_2017_proba = tree.predict_proba(X_2017)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "total_tree = testdata[['stock']].copy()\n",
    "total_tree['predict_prob'] = y_2017_proba[:,1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#选取前50（最有可能性）股票\n",
    "total_tree.sort_values(by='predict_prob',inplace = True,ascending = False)\n",
    "total_tree.reset_index(drop=True,inplace = True)\n",
    "total_tree[:50]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "MarkDown菜单",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
